package com.codeplay.service.impl;

import com.codeplay.entity.Role;
import com.codeplay.entity.Permission;
import com.codeplay.repository.RoleRepository;
import com.codeplay.repository.PermissionRepository;
import com.codeplay.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@Transactional
public class RoleServiceImpl implements RoleService {

    @Autowired
    private RoleRepository roleRepository;

    @Autowired
    private PermissionRepository permissionRepository;

    @Override
    public Role createRole(Role role, Set<String> permissionNames) {
        if (roleRepository.existsByName(role.getName())) {
            throw new RuntimeException("Role already exists");
        }

        Set<Permission> permissions = permissionNames.stream()
                .map(name -> permissionRepository.findByName(name)
                        .orElseThrow(() -> new RuntimeException("Permission not found: " + name)))
                .collect(Collectors.toSet());

        role.setPermissions(permissions);
        return roleRepository.save(role);
    }

    @Override
    public Role updateRole(Long id, Role roleDetails) {
        Role role = getRoleById(id);

        if (!role.getName().equals(roleDetails.getName()) 
            && roleRepository.existsByName(roleDetails.getName())) {
            throw new RuntimeException("Role name already exists");
        }

        role.setName(roleDetails.getName());
        role.setDescription(roleDetails.getDescription());
        
        return roleRepository.save(role);
    }

    @Override
    public void deleteRole(Long id) {
        if (!roleRepository.existsById(id)) {
            throw new RuntimeException("Role not found with id: " + id);
        }
        roleRepository.deleteById(id);
    }

    @Override
    public Role getRoleById(Long id) {
        return roleRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Role not found with id: " + id));
    }

    @Override
    public Role getRoleByName(String name) {
        return roleRepository.findByName(name)
                .orElseThrow(() -> new RuntimeException("Role not found with name: " + name));
    }

    @Override
    public List<Role> getAllRoles() {
        return roleRepository.findAll();
    }

    @Override
    public void assignPermissions(Long roleId, Set<String> permissionNames) {
        Role role = getRoleById(roleId);
        Set<Permission> permissions = role.getPermissions();
        
        permissionNames.forEach(name -> {
            Permission permission = permissionRepository.findByName(name)
                    .orElseThrow(() -> new RuntimeException("Permission not found: " + name));
            permissions.add(permission);
        });
        
        roleRepository.save(role);
    }

    @Override
    public void removePermissions(Long roleId, Set<String> permissionNames) {
        Role role = getRoleById(roleId);
        Set<Permission> permissions = role.getPermissions();
        
        permissions.removeIf(permission -> permissionNames.contains(permission.getName()));
        roleRepository.save(role);
    }

    @Override
    public boolean existsByName(String name) {
        return roleRepository.existsByName(name);
    }

    @Override
    public Set<String> getRolePermissions(Long roleId) {
        Role role = getRoleById(roleId);
        return role.getPermissions().stream()
                .map(Permission::getName)
                .collect(Collectors.toSet());
    }
} 